﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "LayerSettingCommand.h"
#include "IDocument.h"
#include "UniIdentity.h"
#include "GDFoundation/Command.h"
#include "GDFoundation/ILayerSystem.h"
#include "GDFoundation/ILayer.h"
#include "UiDocumentViewUtils.h"
#include "IUiManager.h"
#include "IApplicationWindow.h"
#include "UiCommonDialog.h"
#include "IUserTransaction.h"
#include "ISelection.h"
#include "IElementParameters.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "GDFoundation/LayerBuiltInParameterDefinitions.h"
#include "IUiView.h"
#include "ICanvas.h"
#include <QEvent>

using namespace gcmp;
using namespace gdmp;
namespace Sample
{
   
    bool LayerSettingCommand::IsEnabled() const
    {
        return IsVisible();
    }

    bool LayerSettingCommand::IsVisible() const
    {
        gcmp::IDocument* pDocument = GetDocument();
        if (!pDocument)
            return false;

        if (ILayerSystem::Get(pDocument))
            return true;
        return false;
    }

    LayerSettingDlg::LayerSettingDlg(QWidget* pParent)
        : QDialog(pParent, Qt::WindowFlags())
    {
        if (pParent)
            setParent(pParent, this->windowFlags());
        setFixedWidth(300);
        setFixedHeight(508);
        installEventFilter(this);
        InitDialog();
    }

    LayerSettingDlg::~LayerSettingDlg()
    {
        if (m_opLayerList)
            ClearAllItemInList(m_opLayerList.get());
        m_opLayerList = nullptr;
        m_opOkButton = nullptr;
        m_opCancelButton = nullptr;
        m_opAddButton = nullptr;
    }


    void LayerSettingDlg::OKButtonPushed()
    {
        SaveLayerData();
        QDialog::accept();
    }

    void LayerSettingDlg::CancelButtonPushed()
    {
        QDialog::reject();
    }

    void LayerSettingDlg::AddButtonPushed()
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_opLayerList, L"断言`m_opLayerList`失败",L"GDMPLab",L"2024-03-30");
        std::wstring message;
        UiCommonDialog::ButtonType type = UiCommonDialog::ShowInputBox(L"新建图层", L"请输入新建图层名称(如图层1-图层11):", L"", message);
        if (type == UiCommonDialog::ButtonType::OK)
        {
            message = StringUtil::TrimSpace(message);
            if (message.empty())
            {
                UiCommonDialog::ShowMessageBox(L"图层创建失败", L"图层名为空，创建失败！", static_cast<int>(UiCommonDialog::ButtonType::OK));
                return;
            }
            auto& iter =m_allLayerNames.find(message);
            if (iter != m_allLayerNames.end())
            {
                UiCommonDialog::ShowMessageBox(L"图层创建失败", L"已存在重名图层，创建失败！", static_cast<int>(UiCommonDialog::ButtonType::OK));
                return;
            }
            int nListCount = m_opLayerList->count();
            m_opLayerList->insertItem(nListCount, QString::fromStdWString(message));
            m_opLayerList->setCurrentRow(nListCount);
            m_allNewLayers.insert(message);
            m_allLayerNames.insert(message);
        }
    }

    void LayerSettingDlg::ClearAllItemInList(QListWidget* pListView)
    {
        if (pListView != nullptr)
        {
            int nListCount = pListView->count();
            for (int i = 0; i < nListCount; ++i)
            {
                QListWidgetItem* pItem = pListView->item(i);
                pListView->removeItemWidget(pItem);
                OwnerPtr<QListWidgetItem> opListItem(pItem);
            }
            pListView->clear();
        }
    }

    void LayerSettingDlg::InitDialog()
    {
        setWindowTitle(QString::fromStdWString(L"图层设置"));
        setMouseTracking(true);

        m_opAddButton = NEW_AS_OWNER_PTR(QPushButton, this);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_opAddButton, L"断言`m_opAddButton`失败",L"GDMPLab",L"2024-03-30");
        m_opAddButton->setText(QString::fromStdWString(L"新增"));
        QRect rectButton0(10, 458, 50, 30);
        m_opAddButton->setGeometry(rectButton0);
        m_opOkButton = NEW_AS_OWNER_PTR(QPushButton, this);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_opOkButton, L"断言`m_opOkButton`失败",L"GDMPLab",L"2024-03-30");
        m_opOkButton->setText(QString::fromStdWString(L"确定"));
        QRect rectButton1(180, 458, 50, 30);
        m_opOkButton->setGeometry(rectButton1);
        m_opCancelButton = NEW_AS_OWNER_PTR(QPushButton, this);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_opCancelButton, L"断言`m_opCancelButton`失败",L"GDMPLab",L"2024-03-30");
        m_opCancelButton->setText(QString::fromStdWString(L"取消"));
        QRect rectButton2(240, 458, 50, 30);
        m_opCancelButton->setGeometry(rectButton2);

        connect(m_opAddButton.get(), &QPushButton::clicked, this, &LayerSettingDlg::AddButtonPushed);
        connect(m_opOkButton.get(), &QPushButton::clicked, this, &LayerSettingDlg::OKButtonPushed);
        connect(m_opCancelButton.get(), &QPushButton::clicked, this, &LayerSettingDlg::CancelButtonPushed);

        m_opLayerList = NEW_AS_OWNER_PTR(QListWidget, this);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_opLayerList, L"断言`m_opLayerList`失败",L"GDMPLab",L"2024-03-30");
        QRect rectList(10, 20, 280, 400);
        m_opLayerList->setGeometry(rectList);
        m_opLayerList->setViewMode(QListView::ListMode);
        m_opLayerList->setSortingEnabled(false);
        m_opLayerList->setDragEnabled(false);

        IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"断言`pDoc`失败",L"GDMPLab",L"2024-03-30");
        const ILayerSystem* pLayerSystem = ILayerSystem::Get(pDoc);
        if (pLayerSystem)
        {
            std::map<gcmp::UniIdentity, gcmp::ElementId>  allInfo = pLayerSystem->GetAllLayerInformation();
            int index = 0;
            FOR_EACH(layerInfo, allInfo)
            {
                std::wstring layerName = pLayerSystem->GetLayerNameByGuid(layerInfo.first.GetGuid());
                m_allLayerNames.insert(layerName);
                int nListCount = m_opLayerList->count();
                m_opLayerList->insertItem(nListCount, QString::fromStdWString(layerName));
            }
            m_opLayerList->setCurrentRow(0);
        }
    }



    bool LayerSettingDlg::eventFilter(QObject* object, QEvent* event)
    {
        if (event == nullptr || !object)
            return true;
        if (event->type() == QEvent::MouseButtonPress)
        {
            if (object != m_opLayerList.get())
            {
                this->setFocus();
            }
        }
        return QDialog::eventFilter(object, event);
    }

    void LayerSettingDlg::SaveLayerData()
    {
        IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"断言`pDoc`失败",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_opLayerList, L"断言`m_opLayerList`失败",L"GDMPLab",L"2024-03-30");
        ILayerSystem* pLayerSystem = ILayerSystem::GetFW(pDoc);
        if (pLayerSystem)
        {
            OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"图层数据修改"));
            FOR_EACH(layerName, m_allNewLayers)
            {
                // 此处展示了添加图层的示例，图层需要纳入到图层管理中。
                pLayerSystem->AddLayerElement(layerName);
            }
            QListWidgetItem* pCurItem = m_opLayerList->currentItem();
            if (pCurItem)
            {
                std::wstring curName = pCurItem->text().toStdWString();
                std::map<gcmp::UniIdentity, gcmp::ElementId> allLayerInfo = pLayerSystem->GetAllLayerInformation();
                UniIdentity curUid;
                FOR_EACH(info, allLayerInfo)
                {
                    if (pLayerSystem->GetLayerNameByGuid(info.first.GetGuid()) == curName)
                    {
                        curUid = info.first;
                        break;
                    }
                }

                if (curUid.IsValid())
                {
                    // 此处是通过给选中的图元设置图层属性，即给图元的PARAMETER_UID(LayerBuiltInParameter)嵌入式参数设置图层值。
                    // 1、对于GDMP提供的二维详图线（直线、圆、圆弧等）、填充等创建功能，已给这些图元添加了图层嵌入式参数（缺省值是“通用”），
                    // 并添加了缺省的gcmp::IGraphicsNodeStyleAndMaterialCustomizer样式重载对象。
                    // 此处给新绘制出来的详图线或填充等图元设置图层属性后，这些图元的显示效果将根据其图层在视图对象样式管理中设置的样式进行显示。
                    // 2、对于用户自己制作的图元，或者详图线、填充等图元的缺省的gcmp::IGraphicsNodeStyleAndMaterialCustomizer样式重载对象不满足业务需求，
                    // 用户可以自己实现gcmp::IGraphicsNodeStyleAndMaterialCustomizer样式重载对象设置给图元，具体请参阅gcmp::IGraphicsNodeStyleAndMaterialCustomizer接口说明。
                    // 3、对于用户自己制作的图元，用户可以直接使用GDMP封装的API gdmp::LayerUtils::RegisterLayerData()给该图元添加图层属性、以及图层的视图样式重载处理对象。
                    // 如果需要对已有文档中的图元添加图层，则可以对文档做升级，使用gdmp::LayerUtils::RegisterLayerData()对图元添加图层属性和视图对象样式重载对象。
                    // gdmp::LayerUtils::RegisterLayerData()封装了给图元添加图层属性和视图样式重载对象的细节。
                    ISelection* pSelection = ISelection::Get();
                    DBG_WARN_AND_RETURN_VOID_UNLESS(pSelection, L"pSelection为空？",L"GDMPLab",L"2024-03-30");
                    std::unordered_set<ElementId, ElementIdHash> allSelectIds = pSelection->GetSelectedElements();
                    gcmp::IParameterDefinitionLibrary* pParameterDefLibrary = gcmp::IParameterDefinitionLibrary::Get(pDoc);
                    int parameterId{ -1 };
                    if (pParameterDefLibrary)
                    {
                        parameterId = pParameterDefLibrary->GetParameterDefinitionIdByUid(PARAMETER_UID(LayerBuiltInParameter));
                        FOR_EACH(id, allSelectIds)
                        {
                            IElement* pElement = pDoc->GetElement(id);
                            if (!pElement)
                                continue;
                            IElementParameters* pElementParameters = pElement->GetElementParameters();
                            if (!pElementParameters)
                                continue;
                            IParameter* pParameter = pElementParameters->GetEmbeddedParameterFw(parameterId);
                            if (!pParameter)
                                continue;
                            pParameter->SetValueAsString(GuidUtils::ToString(curUid.GetGuid()));
                        }
                    }

                }
            }
            if (opTransaction)
            {
                bool isOk = opTransaction->Commit();
                DBG_WARN_AND_RETURN_VOID_UNLESS(isOk, L"事务提交失败？",L"GDMPLab",L"2024-03-30");
            }
        }
    }



    gcmp::OwnerPtr<gcmp::IAction> LayerSettingCommand::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
    {
        gcmp::IDocument* pDocument = GetDocument();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDocument, L"断言`pDocument`失败",L"GDMPLab",L"2024-03-30");
        IUiManager* pIUiManager = IUiManager::Get();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pIUiManager,  L"pIUiManager无效",L"GDMPLab",L"2024-03-30");
        IApplicationWindow* pApplicationWindow = pIUiManager->GetApplicationWindow();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pApplicationWindow, L"pApplicationWindow无效",L"GDMPLab",L"2024-03-30");
        UInt64 id = pApplicationWindow->GetApplicationWindowId();
        LayerSettingDlg layerdlg(QWidget::find((WId)id));
        layerdlg.exec();
        IUiView* pCurView = UiDocumentViewUtils::GetCurrentUiView();
        if (pCurView)
        {
            ICanvas* pCanvas = pCurView->GetCanvas();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCanvas, L"断言`pCanvas`失败",L"GDMPLab",L"2024-03-30");
            pCanvas->Refresh();
        }
        return nullptr;
    }

    gcmp::IDocument* LayerSettingCommand::GetDocument() const
    {
        gcmp::IDocument* pDocument = UiDocumentViewUtils::GetCurrentDocument();
        if (pDocument) {
            if (!pDocument->IsFamilyDocument()) {
                return pDocument;
            }
        }
        return nullptr;
    }

    namespace
    {
        //仅作为示例展示使用，注册命令,当析构时移除注册
        gdmp::Command stub{ NEW_AS_OWNER_PTR(LayerSettingCommand) };
    }
}
